#ifndef __M_HOOP_H__
#define __M_HOOP_H__
#include "buffer.hpp"
#include <thread>
#include <condition_variable>
#include <functional>
#include <atomic>

namespace TopLog
{
    enum class AsyncType
    {
        ASYNC_SAFE,
        ASYNC_UNSAFE
    };

    // 异步工作器
    class AsyncTask
    {
    public:
        using ptr = std::shared_ptr<AsyncTask>;
        using Function = std::function<void(Buffer &)>;

        AsyncTask(const Function &cb, AsyncType astype = AsyncType::ASYNC_SAFE) : _stop(false),
                                                                                  _anync_type(astype),
                                                                                  _call_func(cb),
                                                                                  _thread(std::thread(&AsyncTask::threadrun, this)){};
        ~AsyncTask()
        {
            stop_Async();
        }
        void stop_Async()
        {
            _stop = true;           // 停止 true
            _cond_con.notify_all(); // 唤醒所有的工作线程
            _thread.join();
        }
        void push(const char *data, size_t len)
        {
            // 1.无限扩容 --性能测试（非安全） 2.固定大小--生产缓冲区中数据满了就阻塞

            // 写入前先上锁
            std::unique_lock<std::mutex> lock(_mutex);
            // 生产者线程等待, 满足可写就插入 否则 阻塞 （判断是否为安全模式）
            if (_anync_type == AsyncType::ASYNC_SAFE)
            {
                std::cout << "write wait";
                _cond_pro.wait(lock, [&]
                               { return _pro_buf.writeAbleSize() >= len; }); // 使用引用方式捕获值
                std::cout << "write success";
            }

            _pro_buf.push(data, len);
            // 唤醒消费者线程 对缓冲区数据进行处理
            _cond_con.notify_all();
        }

    protected:
        // 工作线程--对消费者缓冲区中数据进行处理，处理完毕后 初始化
        void threadrun()
        {
            while (true)
            {
                // 判断生产者缓冲区有没有数据，有则交换，无则阻塞
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    // 当数据为空和停止同时发生 证明队列为空，具备关闭工作者写入功能
                    if (_stop && _pro_buf.empty())
                    {
                        break;
                    }

                    // 若当时是退出被唤醒，或者有数据被唤醒，则返回真，继续向下运行，否则重新陷入休眠
                    _cond_con.wait(lock, [&]
                                   { return !_pro_buf.empty() || _stop; });
                    _con_buf.swap(_pro_buf);
                    // 唤醒生产者
                    _cond_pro.notify_all();
                }
                // 被唤醒后，对消费缓冲区进行数据处理

                _call_func(_con_buf);
                // 初始化消费缓冲区
                _con_buf.reset();
            }
        }

    private:
        Function _call_func; // 具体对缓冲区数据进行处理的回调函数，由异步工作器使用者传入

    private:
        std::atomic<bool> _stop;
        Buffer _pro_buf; // 生产者
        Buffer _con_buf; // 消费者
        std::mutex _mutex;
        std::condition_variable _cond_pro; // 生产者线程
        std::condition_variable _cond_con; // 消费者线程
        std::thread _thread;
        AsyncType _anync_type;
    };

} // namespace TopLog
#endif
